\ Free problem from Chapter 26 Ham 12:00 11/01/92 \ I suggest that you pass this by until you have worked through \ chapter 26. \ Here is the problem: \ Display a frequency distribution of the characters in this \ file (PROBLEM.SCR). That is, count up how many times each \ character is used and display the information in a way \ convenient to the user. \ That's it. The next screen has a hint, but you should see \ how far you can get just from the problem statement. \ Hint: Define the output first! Ham 12:00 11/01/92 \ Display the counts vertically, with the character in \ question following each count: \ 513 e \ 460 t \ ... \ Don't list characters for which the count is 0. It's best \ to list the characters in descending order on frequency: \ the first character listed is the character most frequently \ used, and down from there. Characters with the same counts \ should be listed in ASCII order. \ Next screen has more hints, but see what you can do with this.\ Second hint(s) Ham 12:00 11/01/92 \ You're going to have to sort, so INCLUDE SORTCODE.SCR \ You'll need both the count and the character's ASCII value \ as sort fields: logical order is by count and ASCII value. \ If you use a pair of slots for each character, one to hold \ the ASCII value and one to hold the count, you can use the \ double-precision operators to manipulate them. \ Think of an array of pairs of slots. How many bytes will you \ need? You could assume that no character value greater than \ 127 is in this file, but clip the value just to be safe. \ So the range of ASCII values is 0 through 127 \ Next screen has more hints, but see what you can do with this.\ More hints Ham 12:00 11/01/92 \ 1. Create and initialize the array. \ 2. Write a loop to accumulate the counts. For each screen, \ take each character and use its ASCII value to go to \ correct cell and increment count. \ 3. Set up sort by writing a word to compare and a word to \ exchange. Don't forget: compare on count; if counts \ are equal, then compare on ASCII value. \ 4. Write a loop to display the sorted table, skipping \ characters for which the count is zero. \ Next screen has more hints, but see what you can do with this.\ Final hints Ham 12:00 11/01/92 \ These words will be helpful. They are put on a separate \ screen because they don't have to be loaded over and over \ as the other words are written and tested. : INCR 1 SWAP +! ; INCLUDE SORTCODE.SCR \ To see program in action, load this and following screens. \ Or simply load entire file: 1 ?SCREENS THRU \ Next screen starts the actual program code. How're you doing? \ Start of the actual program Ham 12:00 11/01/92 EXISTS? SLOT .IF FORGET SLOT .THEN \ for reloads during devel WSIZE 2 * CONSTANT SLOT \ slot for each char and each count CREATE ARRAY 128 SLOT * ALLOT \ looking only for chars 0-127 VARIABLE TOTAL \ As a check, display total number of chars. : TH ( n - adr ) SLOT * ARRAY + ; \ TH converts slot # to adr \ The name TH is due to Chuck Moore. : SETUP 128 0 DO 0 I \ 0 = count, I = ASCII code no. DUP TH 2! LOOP ; \ store in slot according to ASCII code no. \ Display tools Ham 12:00 11/01/92 : .CHAR ( c - ) 2 SPACES \ space after count DUP BL = \ is character blank? IF ." Blank" \ display name for blank ELSE DUP 31 < \ is it a control character? IF PAD C! \ I'll type it (no control chars in PAD 1 TYPE \ this file, but generalize a little) ELSE EMIT THEN \ emit if not a control character THEN CR ; : }PAUSE ( n - ) 1+ 22 MOD 0= \ pause when screen close to full IF CR ." Press key to continue..." KEY DROP CLS THEN ; \ }PAUSE was used in the next screen, my first approach to the \ display word. I decided to go with my second thoughts. \ DISPLAY Ham 12:00 11/01/92 : DISPLAY \ assumes array has been sorted TOTAL OFF \ zero the total CLS 128 0 DO \ do for every character I TH 2@ \ fetch count and character OVER \ copy count to top IF \ nonzero? SWAP DUP \ if yes, put count on top TOTAL +! 6 U.R \ update total and display count .CHAR \ display character ELSE 2DROP LEAVE THEN \ quit when get to the zero counts I }PAUSE \ pause occasionally for user to view LOOP CR TOTAL @ DUP 6 U.R ." TOTAL " ASCII ( EMIT 1024 / . ." screens) " ; \ I found out which cell was count and which char by experiment.\ DISPLAY2 second thoughts Ham 12:00 11/01/92 : DISPLAY2 \ assumes array has been sorted TOTAL OFF \ zero the total CLS 128 0 DO \ do for every character I 24 /MOD 15 * \ y and x coordinates SWAP GOTOXY \ display in columns I TH 2@ \ fetch count and character OVER \ copy count to top IF \ nonzero? SWAP DUP \ if yes, put count on top TOTAL +! 6 U.R \ update total and display count .CHAR \ display character ELSE 2DROP LEAVE THEN \ quit when get to zero counts LOOP ?XY 1+ GOTOXY TOTAL @ DUP 6 U.R ." TOTAL " ASCII ( EMIT 1024 / . ." screens) " ; \ Accumulate counts Ham 12:00 11/01/92 : ACCUM ?SCREENS 0 \ for every screen DO I BLOCK \ get the block 1024 0 \ for each byte in the block DO DUP \ duplicate block address I + \ add current value of I = char offset C@ \ get that character (ASCII value) 127 MIN \ clip it just in case TH \ use value to get correct spot in array WSIZE + \ want addr for count, not char value INCR \ increment the count LOOP DROP \ done with this block, so drop its addr LOOP ; \ loop through all blocks \ Comparison operator Ham 12:00 11/01/92 : COMP ( i1 i2 - f ) \ here's how we compare TH 2@ \ get count and char of first item ROT \ put second item no. on top of stack TH 2@ \ get count and char of second item ROT \ move other char to top of stack 2SWAP \ move counts to top of stack 2DUP = \ are the counts equal? IF 2DROP > \ if yes, compare the character ASCII values ELSE > \ if not, compare the counts -ROT \ and save the flag from the comparison 2DROP \ drop the character values (don't need) THEN ; \ Exchange operator and program Ham 12:00 11/01/92 : SWITCH ( i1 i2 - ) \ switch the two items DUP >R \ save copy of 1st item no. TH 2@ \ get 1st item (count and char) ROT DUP >R \ put 2nd item no. on top and save copy TH 2@ \ get 2nd item (count and char) 2SWAP \ swap 2nd and 1st: 1st now on top R> TH 2! \ retrieve 2nd item no., store 1st there R> TH 2! ; \ retrieve 1st item no., store 2nd there : RUN 128 #ELTS ! ['] COMP PRIOR? ! ['] SWITCH EXCHANGE ! SETUP USING PROBLEM ACCUM SORT DISPLAY2 ; RUN \ See next screen for new challenges. \ New challenges Ham 12:00 11/01/92 \ 1. Did you discover that my routine has a bug? It leaves \ garbage on the stack. Find and fix the bug. (Isolate the \ problem: find which word does it.) \ 2. Modify the program so that it counts all characters, ASCII\ values 0 through 255. The control characters and trans- \ ASCII characters probably won't be found in a screen file \ but are found in binary files (e.g., .EXE and .COM files). \ 3. Modify the program to run on non-screen files, using words\ FREAD and FWRITE and allowing the TOTAL to be larger than \ 65,535. Allow the user to specify the filename. \ 4. Allow for larger counts by using 5-byte slots: one byte \ for the character value, and double-precision for count. \ New challenges Ham 12:00 11/01/92 \ 5. Revise the program so that it offers a choice between \ to the screen and output to the printer. On the printer, \ the output should be printed in columns. People want \ a d g a b c \ b e h and NOT d e f \ c f i g h i \ Do you see how the second was written to make it easy for \ the programmer, not the user? Unacceptable, even sleazy. \ Hint: For the print version, decide how many columns \ you want, and then count how many entries will be printed.\ You can then select the appropriate entries to be printed \ in each row to get balanced columns (last column shorter).